package deepr.src;

import deepr.anno.SchemaType;
import deepr.behaviour.RequestDispose;
import deepr.core.DisposeContext;
import deepr.core.SchemaData;
import deepr.core.SchemaManager;
import deepr.entity.*;
import deepr.exception.DeeprException;
import deepr.handler.SchemaHandler;
import deepr.lib.SpringUtils;
import deepr.src.graph.GraphDispose;
import deepr.src.graph.GraphDisposeContext;
import deepr.src.graph.GraphFilter;
import deepr.src.pg.PgDispose;
import deepr.src.pg.PgDisposeContext;
import deepr.src.pg.PgFilter;
import lombok.Data;
import org.springframework.stereotype.Component;

import java.util.Map;

@Data
@Component
public class DeeprQuery {

  public static <T> DeeprListResponse<T> list(DeeprRequest deeprRequest) throws Exception {
    DeeprListResponse<T> response = (DeeprListResponse<T>) run(deeprRequest, RequestType.LIST);
    response.setPage(deeprRequest.getPage());
    return response;
  }

  public static <T> DeeprInfoResponse<T> info(DeeprRequest deeprRequest) throws Exception {
    return (DeeprInfoResponse<T>) run(deeprRequest, RequestType.INFO);
  }

  public static <T> Response<T> run(DeeprRequest deeprRequest, RequestType method) throws Exception {
    String object = deeprRequest.getObject();
    SchemaData schemaData = SchemaManager.getSchemaData(object);
    SchemaType schemaType = schemaData.getSchemaType();
    DisposeContext ctx;
    RequestDispose dispose;
    switch (schemaType) {
      case PG:
        ctx = new PgDisposeContext();
        ((PgDisposeContext) ctx).setSqlMapper(SpringUtils.getBean("sqlMapper"));
//        DeeprAssert.isTrue(ctx != null, "pgDisposeContext not managed");
        ctx.setSchemaType(SchemaType.PG);
        ctx.setDbFilterBehavior(new PgFilter());
        dispose = new PgDispose();
        ctx.reset();
        break;
      case NEO4J:
        ctx = new GraphDisposeContext();
        ((GraphDisposeContext) ctx).setNeo4jDb(SpringUtils.getBean("neo4jDb"));
//        DeeprAssert.isTrue(ctx != null, "graphDisposeContext not managed");
        ctx.setSchemaType(SchemaType.NEO4J);
        ctx.setDbFilterBehavior(new GraphFilter());
        dispose = new GraphDispose();
        break;
      default:
        throw new DeeprException("Unexpected schemaType: " + schemaType);
    }
    Map<String, Object> params = deeprRequest.getParams();
    ctx.setRequestParams(params);
    ctx.setSchemaData(schemaData);

    Class<?> handler = schemaData.getHandler();
    Response<T> response;
    SchemaHandler h = null;

    if (handler != null) {
      h = (SchemaHandler) SpringUtils.getBean(handler);
      if (method == RequestType.LIST) {
        h.beforeListQuery(ctx, deeprRequest);
      } else
        h.beforeInfoQuery(ctx, deeprRequest);
    }

    if (ctx.getResponse() == null) {
      if (method == RequestType.LIST) {
        response = dispose.list(ctx, deeprRequest);
        response.setObject(object);
        ((DeeprListResponse<T>) response).setPage(deeprRequest.getPage());
      } else
        response = dispose.info(ctx, deeprRequest);
    } else {
      response = ctx.getResponse();
    }
    if (h != null) {
      if (method == RequestType.LIST)
        h.afterListQuery(ctx, (DeeprListResponse<T>) response);
      else
        h.afterInfoQuery(ctx, (DeeprInfoResponse<T>) response);
    }
    return response;
  }


}
